package v1

import dai.core.base.Utils
import org.joml.Matrix4f
import org.joml.Vector3f
import java.lang.RuntimeException

/**
 *  dir 默认为 -z
 *  绕x轴 角度范围为 [-85,85]
 */
open class Obj(
    val position: Vector3f = Vector3f(),
    val rotation: Vector3f = Vector3f(),
    val scale: Vector3f = Vector3f(1f, 1f, 1f),
) {

    companion object {
        const val Debug = true
    }

    var renderItem: RenderItem? = null

    val localMatrix = Matrix4f()
    val worldMatrix = Matrix4f()

    var parent: Obj? = null
    var children: ArrayList<Obj>? = null

    var visible = true

    private fun updateLocalMatrix() {
        localMatrix.setTranslation(position)
        localMatrix.setRotationXYZ(
            Utils.toRadius(rotation.x),
            Utils.toRadius(rotation.y),
            Utils.toRadius(rotation.z)
        )
        localMatrix.scale(scale)
    }

    fun updateMatrix() {

        if (!visible) {
            return
        }

        updateLocalMatrix()
        if (parent == null) {
            worldMatrix.set(localMatrix)
        } else {
            worldMatrix.set(parent!!.worldMatrix).mul(localMatrix)
        }

        // TODO:  提取 worldRotation

        children?.forEach { child ->
            child.updateMatrix()
        }
    }

    fun addToRenderLst(lst: ArrayList<RenderItem>) {
        if (!visible) {
            return
        }
        renderItem?.let {
            it.worldMatrix = worldMatrix
            lst.add(it)
        }
        children?.forEach { child ->
            child.addToRenderLst(lst)
        }
    }

    //---------------------------
    // scene graph
    fun add(obj: Obj) {
        if (obj.parent != null) {
            throw RuntimeException("obj already has parent!")
        }
        if (Debug) {
            val item = this.children?.find { it === obj }
            if (item != null) {
                throw RuntimeException("obj already added!")
            }
        }

        obj.parent = this
        if (children == null) {
            children = ArrayList()
        }
        children!!.add(obj)
    }


    fun cleanup() {
        parent = null
        children?.forEach { child->
            child.cleanup()
        }
        children?.clear()
        children = null
    }
}